package net.xiduth.algorithms;

import java.math.BigInteger;
import java.security.SecureRandom;

/**
 * @author Bart
 * 
 * @since 17-6-2013
 */
public class RSA {

	/**
	 * Generated integer. This will be used to define the prime keys p and q.
	 */
	private final SecureRandom INTEGER = new SecureRandom();

	/** Represents this encryptions private key */
	private BigInteger privateKey;

	/** Represents this encryptions public key */
	private BigInteger publicKey;

	/** The resulting module key that will be used to encrypt data */
	private BigInteger modulus;

	/**
	 * Generates a set of public and private keys. The keys remain prime and are
	 * both in the same bit range. When the keys are generated, a new RSA
	 * instance will be generated in order to encrypt or decrypt data
	 * 
	 * @param hash
	 *            - The key hash
	 * @return - A new RSA instance
	 */
	public RSA(int hash) {
		int name = (int) ((Math.pow(2, 16)) - 1);// 2^16-1
		// generates a new prime key in the 32 bit range
		BigInteger one = new BigInteger("1");
		BigInteger p = BigInteger.probablePrime(hash / 2, INTEGER);
		BigInteger q = BigInteger.probablePrime(hash / 2, INTEGER);
		BigInteger pq = (p.subtract(one)).multiply(q.subtract(one));
		// creates the keys and modulus
		publicKey = new BigInteger(Integer.toString(name));
		privateKey = publicKey.modInverse(pq);
		modulus = p.multiply(q);
	}

	/**
	 * Encrypts public data using {@link BigInteger}
	 * 
	 * @param opcode
	 *            - the data to encrypt
	 * @return - a new encrytped BigInteger
	 */
	public BigInteger encryptMessage(BigInteger opcode) {
		return opcode.modPow(publicKey, modulus);
	}

	/**
	 * Called for login rsa block
	 * 
	 * @param data
	 *            the data
	 * @param exponent
	 *            the exponent
	 * @param modulus
	 *            the modulus
	 * @return the encrypted biginteger
	 */
	public static byte[] encryptMessage(byte[] data, BigInteger exponent,
			BigInteger modulus) {
		return new BigInteger(data).modPow(exponent, modulus).toByteArray();
	}

	/**
	 * Decrypts public data using {@link BigInteger}
	 * 
	 * @param opcode
	 *            - the data to decrypt
	 * @return - a new decrytped BigInteger
	 */
	public BigInteger decryptMessage(BigInteger opcode) {
		return opcode.modPow(privateKey, modulus);
	}
}
